package com.link.base.base.stocksellstorage.service;

import com.link.base.user.model.CoreUser;
import com.link.base.base.accnt.model.Account;
import com.link.base.base.accnt.service.AccountService;
import com.link.base.base.invloc.model.InvProd;
import com.link.base.base.invloc.model.Invloc;
import com.link.base.base.invloc.service.InvProdService;
import com.link.base.base.invloc.service.InvlocService;
import com.link.base.base.invtxn.model.Invtxn;
import com.link.base.base.invtxn.service.InvtxnService;
import com.link.base.base.stocksellstorage.dao.mybatis.mapper.StocktakingMapper;
import com.link.base.base.stocksellstorage.model.Stocktaking;
import com.link.base.base.stocksellstorage.model.StocktakingItem;
import com.link.base.base.stocksellstorage.model.StorageProd;
import com.link.base.base.stocksellstorage.model.StorageProdBalance;
import com.link.base.base.stocksellstorage.model.TransactionDetail;
import com.link.core.cllog.LCLogger;
import com.link.core.basic.dao.mapper.BasicMapper;
import com.link.core.basic.dao.siebel.mapper.BasicMapperSiebel;
import com.link.core.basic.model.BasicModel;
import com.link.core.basic.query.Filter;
import com.link.core.basic.query.QueryParams;
import com.link.core.basic.service.ServiceException;
import com.link.core.basic.service.BasicServiceImpl;
import com.link.core.basic.service.KeyGenerateService;
import com.link.core.util.DateUtil;
import com.link.core.util.UserUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author 程厚霖
 * @date 2018-08-01
 */
@Service
public class StocktakingServiceImpl extends BasicServiceImpl<Stocktaking> implements StocktakingService {

    @Resource
    private StocktakingMapper stocktakingMapper;
    @Resource
    private TransactionDetailService transactionDetailService;
    @Resource
    private StorageProdBalanceService storageProdBalanceService;

    @Resource
    private InvProdService invProdService;
    @Resource
    private InvlocService invlocService;
    @Resource
    private StocktakingItemService stocktakingItemService;
    @Resource
    private InvtxnService invtxnService;
    @Resource
    private AccountService accountService;

    @Resource
    private KeyGenerateService keyGenerateService;

    @Override
    public BasicMapper<Stocktaking> getBasicMapper() {
        return stocktakingMapper;
    }

    @Override
    public BasicMapperSiebel<Stocktaking> getSiebelBasicMapper() throws Exception {
        return null;
    }

    /**
     * 提交盘点单，在保存盘点对象前，需要保存流水交易信息并修改状态，同时保存库存产品的库存量信息
     */
    @Override
    public void commit(Stocktaking entity) throws Exception {
        if (entity.getProdList() == null || entity.getProdList().size() <= 0) {
            throw new ServiceException("SOTCKSELLSTORAGE-001");
        }
        Long id = entity.getId();
        if (null == id) {
            id = keyGenerateService.keyGenerate();
            entity.setId(id);
        }
        entity.setStatus("SUBMITTED");
        //将前端传过来的商品列表转换成流水信息及子表信息
        for (StorageProd item : entity.getProdList()) {
            //更新库存商品对应的子表信息
            StorageProdBalance spb = new StorageProdBalance();
            spb.setStatus("good");
            spb.setUsable("in_hand");
            spb.setQty(Double.parseDouble(item.getStockQty()) - item.getSumQty());
            spb.setStockId(item.getId());
            storageProdBalanceService.insert(spb);
            //更新库存商品对应的子表信息
            if (null == item.getTransactionId()) {
                TransactionDetail td = new TransactionDetail();
                td.setProdId(item.getProdId());
                td.setStockQty(item.getStockQty());
                td.setAmount(String.valueOf(Math.abs(Integer.parseInt(item.getStockQty()) - Math.floor(item.getSumQty()))));
                //判断盘盈、盘亏
                if (Integer.parseInt(item.getStockQty()) - Math.floor(item.getSumQty()) > 0) {
                    td.setType("inventoryprofit");
                    td.setDesInvlocId(item.getInvlocId());
                    td.setDesAvailability("in_hand");
                    td.setDesStatus("good");
                } else {
                    td.setType("inventorylose");
                    td.setOrigInvlocId(item.getInvlocId());
                    td.setOrigAvailability("in_hand");
                    td.setOrigStatus("good");
                }
                td.setTradeDate(DateUtil.dateToStr(new Date(), "yyyy-MM-dd HH:mm:ss"));
                td.setSubmit("Y");
                td.setStockId(id);
                transactionDetailService.insert(td);
            } else {
                TransactionDetail td = new TransactionDetail();
                td.setId(item.getTransactionId());
                td = transactionDetailService.queryById(td);
                td.setStockQty(item.getStockQty());
                td.setAmount(String.valueOf(Math.abs(Integer.parseInt(item.getStockQty()) - Math.floor(item.getSumQty()))));
                //判断盘盈、盘亏
                if (Integer.parseInt(item.getStockQty()) - Math.floor(item.getSumQty()) > 0) {
                    td.setType("inventoryprofit");
                    td.setDesInvlocId(item.getInvlocId());
                    td.setDesAvailability("in_hand");
                    td.setDesStatus("good");
                } else {
                    td.setType("inventorylose");
                    td.setOrigInvlocId(item.getInvlocId());
                    td.setOrigAvailability("in_hand");
                    td.setOrigStatus("good");
                }
                td.setTradeDate(DateUtil.dateToStr(new Date(), "yyyy-MM-dd HH:mm:ss"));
                td.setSubmit("Y");
                transactionDetailService.update(td);
            }
        }
        if (isInsertFlag(entity)) {
            insert(entity);
        } else {
            update(entity);
        }
    }

    @Transactional(rollbackFor = ServiceException.class)
    @Override
    public void insert(Stocktaking entity) throws Exception {
        beforInsert(entity);
        beforUpsert(entity);
        //设置默认值
        postDefaultValue(entity);
        if (null == entity.getId()) {
            entity.setId(keyGenerateService.keyGenerate());
        }
        //进行数据校验
        if (!checkData(entity)) {
            throw new ServiceException("PUBLIC-001");
        }
        entity.setStartDate(DateUtil.dateToStr(new Date(), "yyyy-MM-dd HH:mm:ss"));
        Long accntId = UserUtil.getUser().getAcctId();
        // Long corpId = UserUtil.getUser().getCorpid();
        // Long virtualAccntId = accountService.getVirtualAccount(corpId);
        Account salesParty = accountService.queryById(accntId);
        //仓库
        Invloc salesPartyInvloc = invlocService.getInvloc(salesParty);
        entity.setInventoryId(salesPartyInvloc.getId());
        getBasicMapper().insert(entity);
        if (entity.getStocktakingItemList().isEmpty()) {
            this.beginCalculating(entity);
        }
        afterInsert(entity);
    }


    /**
     * 盘点库存，新建对应行信息
     *
     * @param stocktaking
     * @throws Exception
     */
    @Override
    public void beginCalculating(Stocktaking stocktaking) throws Exception {
        if (null == stocktaking.getId()) {
            throw new ServiceException("SOTCKSELLSTORAGE-001");
        }
        Long acctId = UserUtil.getUser().getAcctId();
        if (null == acctId) {
            throw new ServiceException("SOTCKSELLSTORAGE-003");
        }
        Invloc invloc = new Invloc();
        invloc.setOwnerId(acctId);
        invloc.setTotalFlag(true);
        invloc.setPageFlag(false);
        List<Invloc> invLocs = invlocService.queryByExamplePage(invloc);
        if (invLocs.isEmpty()) {
            throw new RuntimeException("SOTCKSELLSTORAGE-004");
        }
        InvProd invProd = new InvProd();
        invProd.setInvlocId(invLocs.get(0).getId());
        invProd.setProdBrand(stocktaking.getProdBrand());
        invProd.setProdSecBrand(stocktaking.getProdSecBrand());
        invProd.setProdThirdBrand(stocktaking.getProdThirdBrand());
        QueryParams qps = new QueryParams();
        qps.addFilter(new Filter("headId10123213133", "invlocId", Filter.OP_EQUAL, invProd.getInvlocId().toString()));
        invProd = (InvProd) BasicModel.transformClass(invProd, qps);
        invProd.setPageFlag(false);
        List<InvProd> invProdList = invProdService.queryByExamplePage(invProd);
        invProdList.forEach(f -> {
            if (f.getCount() != 0) {
                StocktakingItem stocktakingItem = new StocktakingItem();
                stocktakingItem.setStocktakingId(stocktaking.getId());
                stocktakingItem.setProdId(f.getProdId());
                stocktakingItem.setProdCode(f.getProdCode());
                stocktakingItem.setProdName(f.getProdName());
                stocktakingItem.setActualStatus("good");
                BigDecimal d1 = new BigDecimal(Double.toString(f.getCount()));
                stocktakingItem.setStockQty(d1.toString());
                try {
                    stocktakingItemService.insert(stocktakingItem);
                } catch (Exception e) {
                    LCLogger.withException(e);
                }
            }
        });
    }

    /**
     * 插入头行
     *
     * @param entity
     * @return Stocktaking
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public Stocktaking upsertHeadAndLine(Stocktaking entity) throws Exception {
        String newStr = "NEW";
        if (null == entity.getId() || newStr.equals(entity.getRow_status())) {
            //如果订单Id为空或者状态为新建，则新建订单。否则更新
            entity.setId(keyGenerateService.keyGenerate());
            //插入头
            this.insert(entity);
            //插入行
            List<StocktakingItem> stocktakingItemList = entity.getStocktakingItemList();
            if (!CollectionUtils.isEmpty(stocktakingItemList)) {
                stocktakingItemList.forEach(f -> {
                    if (null != f.getId()) {
                        throw new ServiceException("SOTCKSELLSTORAGE-005");
                    }
                    f.setStocktakingId(entity.getId());
                    try {
                        stocktakingItemService.insert(f);
                    } catch (Exception e) {
                        LCLogger.withException(e);
                    }
                });
            }
        } else {
            //更新
            this.update(entity);
            //虚拟仓库
            Invloc virtualAccountInvloc = invlocService.getFictitiousInvloc();
            StocktakingItem queryParam = new StocktakingItem();
            queryParam.setStocktakingId(entity.getId());
            queryParam.setPageFlag(false);
            List<StocktakingItem> stocktakingItemOldList = stocktakingItemService.queryByExamplePage(queryParam);
            List<StocktakingItem> stocktakingItemList = entity.getStocktakingItemList();
            if (null == stocktakingItemList) {
                stocktakingItemList = new ArrayList<>();
            }
            if (null == stocktakingItemOldList) {
                stocktakingItemOldList = new ArrayList<>();
            }
            //比较，把没有的删掉。把新增的加入
            for (StocktakingItem stocktakingItemOld : stocktakingItemOldList) {
                Long itemId = stocktakingItemOld.getId();
                boolean existFlag = false;
                for (StocktakingItem stocktakingItemNew : stocktakingItemList) {
                    //把没有的删除掉
                    Long newItemId = stocktakingItemNew.getId();
                    if (null != newItemId && itemId.equals(newItemId)) {
                        existFlag = true;
                        break;
                    }
                }
                if (!existFlag) {
                    //把没有的删掉
                    stocktakingItemService.deleteById(stocktakingItemOld);
                }
            }
            for (StocktakingItem item : stocktakingItemList) {
                item.setStocktakingId(entity.getId());
                if (null == item.getId()) {
                    stocktakingItemService.insert(item);
                } else {
                    stocktakingItemService.update(item);
                }
                if (!"SUBMITTED".equals(entity.getStatus())) {
                    continue;
                }
                Double diffQty = Double.parseDouble(item.getStockQty()) - Double.parseDouble(item.getActualQty());
                if (diffQty < 0) {
                    //盘盈
                    //生成记录
                    Invtxn invtxn = new Invtxn();
                    Long prodId = item.getProdId();
                    //添加交易记录:类型、来源仓库、目的仓库
                    invtxn.setType("inventoryprofit");
                    invtxn.setOrigInvlocId(virtualAccountInvloc.getId());
                    invtxn.setDesInvlocId(entity.getInventoryId());
                    invtxn.setProdId(prodId);
                    invtxn.setAmount(Math.abs(diffQty));
                    invtxn.setTradeDate(DateUtil.dateToStr(new Date(), "yyyy-MM-dd HH:mm:ss"));
                    invtxn.setDesAvailability("in_hand");
                    invtxn.setDesStatus("good");
                    invtxn.setNote(entity.getCalTask());
                    invtxn.setSourceId(entity.getId());
                    invtxn.setOrgId(entity.getOrgId());
                    CoreUser user = UserUtil.getUser();
                    if (invtxn.getOrgId() == null) {
                        invtxn.setOrgId(user.getOrgId());
                    }
                    invtxnService.insert(invtxn);
                    invtxnService.goodConfirm(invtxn.getId());
                } else if (diffQty > 0) {
                    Invtxn invtxn = new Invtxn();
                    Long prodId = item.getProdId();
                    //添加交易记录:类型、来源仓库、目的仓库
                    invtxn.setType("inventorylose");
                    invtxn.setOrigInvlocId(entity.getInventoryId());
                    invtxn.setDesInvlocId(virtualAccountInvloc.getId());
                    invtxn.setProdId(prodId);
                    invtxn.setAmount(diffQty);
                    invtxn.setTradeDate(DateUtil.dateToStr(new Date(), "yyyy-MM-dd HH:mm:ss"));
                    invtxn.setOrigAvailability("in_hand");
                    invtxn.setOrigStatus("good");
                    invtxn.setNote(entity.getCalTask());
                    invtxn.setSourceId(entity.getId());
                    invtxn.setOrgId(entity.getOrgId());
                    CoreUser user = UserUtil.getUser();
                    if (invtxn.getOrgId() == null) {
                        invtxn.setOrgId(user.getOrgId());
                    }
                    invtxnService.insert(invtxn);
                    invtxnService.goodConfirm(invtxn.getId());
                }
            }

            // TODO: 2018/8/3 盘点差异是盘盈盘亏操作

        }
        Stocktaking stocktaking = this.queryById(entity.getId());
        StocktakingItem queryParam = new StocktakingItem();
        queryParam.setStocktakingId(entity.getId());
        queryParam.setPageFlag(false);
        List<StocktakingItem> stocktakingItems = stocktakingItemService.queryByExamplePage(queryParam);
        stocktaking.setStocktakingItemList(stocktakingItems);
        return stocktaking;
    }

    /**
     * 删除前操作
     *
     * @param stocktaking
     * @throws Exception
     */
    @Override
    public void beforDelete(Stocktaking stocktaking) throws Exception {
        if (null == stocktaking.getId()) {
            throw new ServiceException("SOTCKSELLSTORAGE-006");
        }
        stocktaking = this.queryById(stocktaking);
        String newStatus = "New";
        if (!newStatus.equals(stocktaking.getStatus())) {
            throw new ServiceException("SOTCKSELLSTORAGE-007");
        }
    }

    /**
     * 删除盘点头后删除盘点行
     *
     * @param stocktaking
     * @throws Exception
     */
    @Override
    public void afterDelete(Stocktaking stocktaking) throws Exception {
        StocktakingItem stocktakingItem = new StocktakingItem();
        stocktakingItem.setStocktakingId(stocktaking.getId());
        stocktakingItem.setLoginCorpId(UserUtil.getUser().getLoginCorpId());
        stocktakingItemService.deleteByStocktakingId(stocktakingItem);
    }
}
